﻿using System;
using System.Linq;
using Caliburn.Micro;

namespace SS.WPF.Framework.ViewModel.Navigation
{
    /// <summary>
    /// The class implement interface INavigationNode that is used to present a NavigationNode
    /// </summary>
    public class NavigationNode : PropertyChangedBase, INavigationNode, IEditorDescription
    {
        #region Properties & Fields

        private INavigationNode[] _removedChildren;

        public object Input { get; set; }

        public Type EditorType { get; set; }

        public EditingStatus EditingStatus
        {
            get
            {
                if (this.IsDeleted)
                {
                    return EditingStatus.Deleted;
                }

                if (this.HasError)
                {
                    return EditingStatus.Error;
                }

                if (this.IsAdded)
                {
                    return EditingStatus.Added;
                }

                return this.IsEditorDirty ? EditingStatus.Modified : EditingStatus.None;
            }
        }

        private string _displayName;
        public string DisplayName
        {
            get
            {
                return this._displayName;
            }
            set
            {
                this._displayName = value;
                this.NotifyOfPropertyChange(() => this.DisplayName);
            }
        }

        private bool _hasError;
        public bool HasError
        {
            get
            {
                return this._hasError;
            }
            set
            {
                if (value)
                {
                    this._hasError = true;
                }
                else
                {
                    if (this.Input is IEditor && ((IEditor)this.Input).HasError)
                    {
                        this._hasError = true;
                    }
                    else
                    {
                        this._hasError = this.Children != null && this.Children.Any(x => x.HasError);
                    }
                }

                var current = this.Parent;
                while (current != null)
                {
                    current.HasError = this.HasError;
                    current = current.Parent;
                }

                this.NotifyOfPropertyChange(() => this.HasError);
                this.NotifyOfPropertyChange(() => this.EditingStatus);
            }
        }

        private bool _isEditorDirty;
        public bool IsEditorDirty
        {
            get
            {
                return this._isEditorDirty;
            }
            set
            {
                if (value)
                {
                    this._isEditorDirty = true;
                }
                else
                {
                    if (this.Input is IEditor && ((IEditor)this.Input).IsEditorDirty)
                    {
                        this._isEditorDirty = true;
                    }
                    else
                    {
                        this._isEditorDirty = this.Children != null && this.Children.Any(x => x.IsEditorDirty);
                    }
                }

                var current = this.Parent;
                while (current != null)
                {
                    current.IsEditorDirty = this.IsEditorDirty;
                    current = current.Parent;
                }

                this.NotifyOfPropertyChange(() => this.IsEditorDirty);
                this.NotifyOfPropertyChange(() => this.EditingStatus);
            }
        }

        #endregion

        #region Implementation of INavigationNode

        private INavigationNode _parent;
        public INavigationNode Parent
        {
            get
            {
                return this._parent;
            }
            set
            {
                this._parent = value;
                this.NotifyOfPropertyChange(() => this.Parent);
            }
        }

        private INavigationNode[] _children;
        public INavigationNode[] Children
        {
            get
            {
                return this._children;
            }
            set
            {
                this._children = value;
                this.NotifyOfPropertyChange(() => this.Children);
            }
        }

        private bool _isAdded;
        public bool IsAdded
        {
            get
            {
                return this._isAdded;
            }
            set
            {
                this._isAdded = value;
                this.NotifyOfPropertyChange(() => this.IsAdded);
                this.NotifyOfPropertyChange(() => this.EditingStatus);
            }
        }

        private bool _isSelected;
        public bool IsSelected
        {
            get
            {
                return this._isSelected;
            }
            set
            {
                this._isSelected = value;
                this.NotifyOfPropertyChange(() => this.IsSelected);
            }
        }

        private bool _isExpanded;
        public bool IsExpanded
        {
            get
            {
                return this._isExpanded;
            }
            set
            {
                this._isExpanded = value;
                this.NotifyOfPropertyChange(() => this.IsExpanded);
            }
        }

        private bool _isDeleted;
        public bool IsDeleted
        {
            get
            {
                return this._isDeleted;
            }
            set
            {
                this._isDeleted = value;
                if (this._isDeleted)
                {
                    this._removedChildren = this.Children;
                    this.Children = null;
                }
                else
                {
                    if (this._removedChildren != null)
                    {
                        this.Children = this._removedChildren;
                        this._removedChildren = null;
                    }
                }

                this.NotifyOfPropertyChange(() => this.IsDeleted);
                this.NotifyOfPropertyChange(() => this.EditingStatus);
            }
        }

        #endregion
    }
}
